<?php
require_once 'Zend/Captcha/Base.php';

require_once 'NP/Service/Asirra.php';

/**
 * Asirra captcha adapter, which can be used for implementing
 * captcha driven by Asirra web service.
 *
 * @author Nikola Posa <posa.nikola@gmail.com>
 * @license http://opensource.org/licenses/gpl-3.0.html GNU General Public License
 */
class NP_Captcha_Asirra extends Zend_Captcha_Base
{
    const ASIRRA_TICKET_FIELD = 'Asirra_Ticket';

    const MISSING_TICKET = 'missingTicket';
    const INCORRECT_SELECTION = 'incorrectSelection';
    
    /**
     * NP_Service_Asirra service instance.
     * 
     * @var NP_Service_Asirra
     */
    protected $_service;

    /**
     * Error messages.
     *
     * @var array
     */
    protected $_messageTemplates = array(
        self::MISSING_TICKET      => 'Missing Assira ticket',
        self::INCORRECT_SELECTION => 'Please correctly identify the cats',
    );

    /**
     * Whether to use decorator for rendering JS code, which is
     * necessary to trigger the Asirra validation process.
     *
     * @var bool
     */
    protected $_useJsDecorator = true;

    /**
     * Constructor
     *
     * @param  array|Zend_Config $options
     * @return void
     */
    public function  __construct($options = null)
    {
        $this->setService(new NP_Service_Asirra());
        
        parent::__construct($options);
    }

    /**
     * Definded by Zend_Captcha_Base.
     *
     * Set single option for the object
     *
     * @param string $key
     * @param string $value
     * @return NP_Captcha_Asirra
     */
    public function setOption($key, $value)
    {
        //Allowing setting of service options.
        $serviceOptions = array_keys($this->_service->getOptions());
        if (in_array($key, $serviceOptions)) {
            $this->_service->setOption($key, $value);
            return $this;
        }

        return parent::setOption($key, $value);
    }

    /**
     * Set service object.
     *
     * @param NP_Service_Asirra $service
     * @return NP_Captcha_Asirra
     */
    public function setService(NP_Service_Asirra $service)
    {
        $this->_service = $service;
        
        return $this;
    }

    /**
     * Retrieve Asirra service object.
     *
     * @return NP_Service_Asirra
     */
    public function getService()
    {
        return $this->_service;
    }

    /**
     * Sets $_useJsDecorator flag.
     *
     * @param bool $useJsDecorator
     * @return NP_Captcha_Asirra
     */
    public function setUseJsDecorator($useJsDecorator)
    {
        $this->_useJsDecorator = (bool)$useJsDecorator;

        return $this;
    }

    /**
     * Gets $_useJsDecorator flag.
     *
     * @return bool
     */
    public function getUseJsDecorator()
    {
        return $this->_useJsDecorator;
    }

    /**
     * Definded by Zend_Captcha_Adapter.
     *
     * Generate a new captcha
     *
     * @return string new captcha ID
     */
    public function generate()
    {
        return "";
    }

    /**
     * Definded by Zend_Captcha_Adapter.
     * 
     * Display the captcha
     *
     * @param  Zend_View_Interface $view
     * @param  mixed $element
     * @return string
     */
    public function render(Zend_View_Interface $view = null, $element = null)
    {
        return $this->_service->getHtml();
    }

    /**
     * Validate captcha
     *
     * @see    Zend_Validate_Interface::isValid()
     * @param  mixed $value
     * @param  mixed $context
     * @return boolean
     */
    public function isValid($value, $context = null)
    {
        if (!is_array($value) && !is_array($context)) {
            $this->_error(self::MISSING_TICKET);
            return false;
        }

        if (!is_array($value) && is_array($context)) {
            $value = $context;
        }

        if (empty($value[self::ASIRRA_TICKET_FIELD])) {
            $this->_error(self::INCORRECT_SELECTION);
            return false;
        }

        $response = $this->_service->verify($value[self::ASIRRA_TICKET_FIELD]);

        if (!$response->isValid()) {
            $this->_error(self::INCORRECT_SELECTION);
            return false;
        }

        return true;
    }

    /**
     * Definded by Zend_Captcha_Adapter.
     *
     * Get optional decorator
     *
     * @return string|null
     */
    public function getDecorator()
    {
        return ($this->_useJsDecorator) ? 'Captcha_AsirraCheckIfHuman' : null;
    }
}